/**
 * Copyright (c) Software Institute of PKU
 * All rights reserved. 
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 */
package edu.pku.sei.transformation.editor.internal;

import java.util.ArrayList;
import java.util.List;

import edu.pku.sei.modeler.exceptions.FactoryNotFoundException;
import edu.pku.sei.modeler.model.common.ModelRegistry;
import edu.pku.sei.modeler.model.core.MetaDataType;
import edu.pku.sei.modeler.model.core.MetaModel;
import edu.pku.sei.modeler.model.core.MetaPackage;
import edu.pku.sei.modeler.model.core.MetaPrimitiveType;
import edu.pku.sei.modeler.model.structure.MetaDiagram;
import edu.pku.sei.transformation.editor.model.ModelFactory;
import edu.pku.sei.transformation.editor.model.ModelPackage;

/**
 * @generated
 * 
 */
public class TransformationEditorModelRoot {
	protected MetaModel model;
	public static final String PRIMITIVE_PACKAGE = "Primitive Type";
	public static final String METAMODEL_PACKAGE = "Meta-Model";
	public static final String TRANSFORMATION_PACKAGE = "transformation package";
	public static final String EXECUTION_PACKAGE = "execution package";
	public static final String GOAL_PACKAGE = "goal package";
	public static final String TEST_PACKAGE = "test package";
	public static final String MODEL_TYPE_PACKAGE = "model type package";

	public TransformationEditorModelRoot() {
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see edu.pku.modeler.internal.IProjectModelRoot#getAllInstances()
	 */
	public List getAllInstances() {
		List list = this.getDiagramInstances();
		// list.add(this.getModelInstances());
		return list;
	}

	public List getDiagramInstances() {
		List list = new ArrayList();
		// diagramRoot.getContentRecursive(list);
		return list;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.pku.modeler.internal.IProjectModelRoot#getInstancesOf(java.lang.String
	 * )
	 */
	public List getInstancesOf(String typeName) {
		List list = getAllInstances();
		ArrayList result = new ArrayList();
		if (typeName.equals("Type")) {
			for (int i = 0; i < list.size(); i++) {
				if (list.get(i) instanceof MetaDataType) {
					result.add(list.get(i));
				}
			}
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see edu.pku.modeler.internal.IProjectModelRoot#initModel()
	 */
	public void initModel(String modelName) {
		ModelFactory factory = new ModelFactory();
		ModelPackage pkg = new ModelPackage();
		// create model
		model = (MetaModel) factory.createElement(ModelPackage.__METAMODEL__,
				false);
		// register the model to ModelRegistry
		ModelRegistry.getRegistry().registerModel(model, factory, pkg);
		// register the model to package
		factory.registerToPackage(model, ModelPackage.__METAMODEL__);

		// add top package
		// MetaPackage transformationPackage = factory.createMetaPackage();
		// transformationPackage.s

		// add transformtion package
		MetaPackage defaultPackage = factory.createMetaPackage();
		defaultPackage.setName(TRANSFORMATION_PACKAGE);
		defaultPackage.setModel(model);
		model.setName(modelName);
		model.getPackages().add(defaultPackage);

		// add execution package
		MetaPackage executionPackage = factory.createMetaPackage();
		executionPackage.setName(EXECUTION_PACKAGE);
		model.getPackages().add(executionPackage);

		// add requirement package
		MetaPackage requirementPackage = factory.createMetaPackage();
		requirementPackage.setName(GOAL_PACKAGE);
		model.getPackages().add(requirementPackage);

		// add test package
		MetaPackage testPackage = factory.createMetaPackage();
		testPackage.setName(TEST_PACKAGE);
		model.getPackages().add(testPackage);

		// add model type package
		MetaPackage modelTypePackage = factory.createMetaPackage();
		modelTypePackage.setName(MODEL_TYPE_PACKAGE);
		model.getPackages().add(modelTypePackage);

		// add primitive package and primitive types
		// by default, the target modeling tool need not these primitive types
		initPrimitiveType(factory);

		// add metamodel package
		MetaPackage metaModelPackage = factory.createMetaPackage();
		metaModelPackage.setName(METAMODEL_PACKAGE);
		model.getPackages().add(metaModelPackage);
	}

	protected void initPrimitiveType(ModelFactory factory) {
		// MetaModel primitiveType = factory.createMetaModel();
		// primitiveType.setName("primitiveType");
		//		
		MetaPackage primitiveTypePackage = factory.createMetaPackage();
		primitiveTypePackage.setName(PRIMITIVE_PACKAGE);
		// primitiveType.getPackages().add(primitiveTypePackage);

		MetaPrimitiveType booleanType = factory.createMetaPrimitiveType();
		booleanType.setName("boolean");
		booleanType.setModel(model);
		primitiveTypePackage.getNamedElements().add(booleanType);
		model.registerType(booleanType);

		MetaPrimitiveType integerType = factory.createMetaPrimitiveType();
		MetaPrimitiveType floatType = factory.createMetaPrimitiveType();
		MetaPrimitiveType doubleType = factory.createMetaPrimitiveType();
		MetaPrimitiveType charType = factory.createMetaPrimitiveType();
		MetaPrimitiveType stringType = factory.createMetaPrimitiveType();
		integerType.setName("int");
		floatType.setName("float");
		doubleType.setName("double");
		charType.setName("char");
		stringType.setName("String");

		integerType.setModel(model);
		floatType.setModel(model);
		doubleType.setModel(model);
		charType.setModel(model);
		stringType.setModel(model);

		model.getPackages().add(primitiveTypePackage);
		primitiveTypePackage.getNamedElements().add(integerType);
		primitiveTypePackage.getNamedElements().add(floatType);
		primitiveTypePackage.getNamedElements().add(doubleType);
		primitiveTypePackage.getNamedElements().add(charType);
		primitiveTypePackage.getNamedElements().add(stringType);

		model.registerType(integerType);
		model.registerType(floatType);
		model.registerType(doubleType);
		model.registerType(charType);
		model.registerType(stringType);
	}

	/**
	 * @return Returns the modelName.
	 */
	public String getModelName() {
		return model.getName();
	}

	/**
	 * @param modelName
	 *            The modelName to set.
	 */
	public void setModelName(String modelName) {
		model.setName(modelName);
	}

	public void addToModel(Object modelEle, MetaDiagram diagram) {
		// MetaModelContentProvider provider =
		// (MetaModelContentProvider)treeViewer.getContentProvider();
		// Object parent = provider.getParent(diagram);
		// if(parent instanceof MetaPackage) {
		// MetaPackage p = (MetaPackage)parent;
		// if(modelEle instanceof MetaNamedElement) {
		// p.getNamedElements().add(modelEle);
		// }
		// else {
		// p.getOtherElements().add(modelEle);
		// }
		// model.registerType(modelEle);
		// }
		// if(modelEle instanceof MetaModelElement) {
		// ((MetaModelElement)modelEle).setModel(model);
		// ((MetaModelElement)modelEle).addPropertyChangeListener(provider.
		// getModelListener());
		// }
		// treeViewer.refresh(parent);
	}

	// ????Editor?????????????treeViewer??????
	public void removeFromModel(Object modelEle, MetaDiagram diagram) {
		// MetaModelContentProvider provider =
		// (MetaModelContentProvider)treeViewer.getContentProvider();
		// Object parent = provider.getParent(diagram);
		// if(parent instanceof MetaPackage) {
		// MetaPackage p = (MetaPackage)parent;
		// if(modelEle instanceof MetaNamedElement) {
		// p.getNamedElements().remove(modelEle);
		// }
		// else {
		// p.getOtherElements().remove(modelEle);
		// }
		// }
		// treeViewer.refresh(parent);
	}

	// /**
	// * @return Returns the treeViewer.
	// */
	// public TreeViewer getTreeViewer() {
	// return treeViewer;
	// }
	// /**
	// * @param treeViewer The treeViewer to set.
	// */
	// public void setTreeViewer(TreeViewer treeViewer) {
	// this.treeViewer = treeViewer;
	// }

	public boolean hasDiagram(Object diagram) {
		if (model == null)
			return false;
		List<MetaPackage> pkgs = model.getPackages();
		for (MetaPackage pkg : pkgs) {
			if (hasDiagram(pkg, diagram))
				return true;
		}
		return false;
	}

	private boolean hasDiagram(MetaPackage parent, Object diagram) {
		List<MetaDiagram> diags = parent.getDiagrams();
		for (MetaDiagram diag : diags) {
			if (diag == diagram)
				return true;
		}
		List<MetaPackage> pkgs = parent.getSubPackages();
		for (MetaPackage pkg : pkgs) {
			if (hasDiagram(pkg, diagram))
				return true;
		}
		return false;
	}

	/**
	 * @return Returns the model.
	 */
	public MetaModel getModel() {
		return model;
	}

	/**
	 * @param model
	 *            The model to set.
	 */
	public void setModel(MetaModel model) {
		this.model = model;
	}

	public static MetaPackage getMetaModelPkg(MetaModel projectModel) {
		for (Object obj : projectModel.getPackages()) {
			if (obj instanceof MetaPackage
					&& TransformationEditorModelRoot.METAMODEL_PACKAGE
							.equals(((MetaPackage) obj).getName())) {
				return (MetaPackage) obj;
			}

		}
		return null;
	}

	public static MetaPackage getModelTypePkg(MetaModel projectModel) {
		for (Object obj : projectModel.getPackages()) {
			if (obj instanceof MetaPackage
					&& TransformationEditorModelRoot.MODEL_TYPE_PACKAGE
							.equals(((MetaPackage) obj).getName())) {
				return (MetaPackage) obj;
			}

		}
		return null;
	}

	public static MetaPackage getTransformationPackage(MetaModel projectModel) {
		for (Object obj : projectModel.getPackages()) {
			if (TransformationEditorModelRoot.TRANSFORMATION_PACKAGE
					.equals(((MetaPackage) obj).getName())) {
				return (MetaPackage) obj;
			}
		}
		ModelFactory f;
		try {
			f = (ModelFactory) ModelRegistry.getRegistry().getFactory(
					projectModel);
			MetaPackage pkg = f.createMetaPackage();
			pkg.setName(TransformationEditorModelRoot.TRANSFORMATION_PACKAGE);
			projectModel.getPackages().add(0, pkg);
			return pkg;
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (FactoryNotFoundException e) {
			e.printStackTrace();
		}
		return null;
	}

	public static MetaPackage getPrimitivePackage(MetaModel projectModel) {
		for (Object obj : projectModel.getPackages()) {
			if (obj instanceof MetaPackage) {
				if (TransformationEditorModelRoot.PRIMITIVE_PACKAGE
						.equals(((MetaPackage) obj).getName())) {
					return (MetaPackage) obj;
				}
			}
		}
		return null;
	}
}
